﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;

using System.Data;
using System.Data.Entity;
using System.Net;
using System.Web.Mvc;
using OnlineMediaAnalyzer.Models;
using System.Xml;
using System.Globalization;
using System.IO;

namespace OnlineMediaAnalyzer
{
    public class AnalysisTask
    {
        public static void Process(List<Article> articles, List<Feed> feeds)
        {
            using (OnlineMediaAnalyzerContext db = new OnlineMediaAnalyzerContext())
            {
                List<PartyMember> partyMembers = db.PartyMembers.ToList();
                List<PartyKeyword> partyKeywords = db.PartyKeywords.ToList();
                List<Party> parties = db.Parties.ToList();

                List<FeedParty> feedParties = AddNewFeedParties(db, feeds, parties);
                List<FeedStatistic> feedStatistics = AddNewFeedStatistics(db, feeds);
                List<MemberMention> memberMentions = AddNewMemberMentions(db, feeds, partyMembers);

                db.SaveChanges();

                
                UpdateFeedPartiesAndStatistics(db, articles, feedParties, feedStatistics, partyMembers, partyKeywords);
                UpdateMemberMentions(db, articles, memberMentions, partyMembers);

                db.SaveChanges();
            }
        }

        public static List<FeedParty> AddNewFeedParties(OnlineMediaAnalyzerContext db, List<Feed> feeds, List<Party> parties)
        {
            DateTime now = DateTime.Now;
            List<FeedParty> feedParties = db.FeedParties.Where(x => x.Date.Month == now.Month && x.Date.Year == now.Year).ToList();

            foreach (Feed feed in feeds)
            {
                foreach (Party party in parties)
                {
                    bool exists = false;
                    foreach (FeedParty feedParty in feedParties)
                    {
                        if (feedParty.Party.ID == party.ID && feedParty.Feed.ID == feed.ID)
                        {
                            exists = true;
                            break;
                        }
                    }
                    if (!exists)
                    {
                        FeedParty newFeedParty = db.FeedParties.Create();
                        newFeedParty.Date = now;
                        newFeedParty.ArticlesCount = 0;
                        newFeedParty.ArticlesMemberCount = 0;
                        newFeedParty.FeedID = feed.ID;
                        newFeedParty.LastFetchTime = now;
                        newFeedParty.NegArticlesCount = 0;
                        newFeedParty.PartyID = party.ID;
                        newFeedParty.PosArticlesCount = 0;

                        db.FeedParties.Add(newFeedParty);
                        feedParties.Add(newFeedParty);
                    }
                }
            }
            return feedParties;
        }

        public static List<FeedStatistic> AddNewFeedStatistics(OnlineMediaAnalyzerContext db, List<Feed> feeds)
        {
            DateTime now = DateTime.Now;
            List<FeedStatistic> feedStatistics = db.FeedStatistics.Where(x => x.Date.Month == now.Month && x.Date.Year == now.Year).ToList();

            foreach (Feed feed in feeds)
            {
                bool exists = false;
                foreach (FeedStatistic feedStatistic in feedStatistics)
                {
                    if (feedStatistic.Feed.ID == feed.ID)
                    {
                        exists = true;
                        break;
                    }
                }
                if (!exists)
                {
                    FeedStatistic newFeedStatistic = db.FeedStatistics.Create();
                    newFeedStatistic.Date = now;
                    newFeedStatistic.ArticlesCount = 0;
                    newFeedStatistic.FeedID = feed.ID;
                    newFeedStatistic.MultiPartyArticlesCount = 0;
                    newFeedStatistic.NegPoliticalArticlesCount = 0;
                    newFeedStatistic.PartyMentionsCount = 0;
                    newFeedStatistic.PoliticalArticlesCount = 0;
                    newFeedStatistic.PosPoliticalArticlesCount = 0;

                    db.FeedStatistics.Add(newFeedStatistic);
                    feedStatistics.Add(newFeedStatistic);
                }
            }
            return feedStatistics;
        }

        public static List<MemberMention> AddNewMemberMentions(OnlineMediaAnalyzerContext db, List<Feed> feeds, List<PartyMember> partyMembers)
        {
            DateTime now = DateTime.Now;
            List<MemberMention> memberMentions = db.MemberMentions.Where(x => x.Date.Month == now.Month && x.Date.Year == now.Year).ToList();
            foreach (Feed feed in feeds)
            {
                foreach (PartyMember partyMember in partyMembers)
                {
                    bool exists = false;
                    foreach (MemberMention memberMention in memberMentions)
                    {
                        if (memberMention.PartyMember.ID == partyMember.ID && memberMention.Feed.ID == feed.ID)
                        {
                            exists = true;
                            break;
                        }
                    }
                    if (!exists)
                    {
                        MemberMention memberMention = db.MemberMentions.Create();
                        memberMention.Date = now;
                        memberMention.FeedID = feed.ID;
                        memberMention.MentionsCount = 0;
                        memberMention.NegMentionsCount = 0;
                        memberMention.PartyMemberID = partyMember.ID;
                        memberMention.PosMentionsCount = 0;

                        db.MemberMentions.Add(memberMention);
                        memberMentions.Add(memberMention);
                    }
                }
            }
            return memberMentions;
        }

        public static void UpdateFeedPartiesAndStatistics(OnlineMediaAnalyzerContext db, List<Article> articles, List<FeedParty> feedParties, List<FeedStatistic> feedStatistics, List<PartyMember> partyMembers, List<PartyKeyword> partyKeywords)
        {
            DateTime now = DateTime.Now;
            foreach (Article article in articles)
            {
                List<Party> initialMentionedParties = GetPartyMentions(article, partyKeywords);
                List<PartyMember> initialMentionedMembers = GetMemberMentions(article, partyMembers);
                List<Party> mentionedPartiesByTheirMembers = MemberMentionsToParties(initialMentionedMembers);
                List<Party> mentionedPartiesTotal = SumPartyAndMemberMentions(initialMentionedParties, initialMentionedMembers);
                //Update feedParties
                foreach (FeedParty feedParty in feedParties) 
                {
                    if (article.Feed.ID == feedParty.Feed.ID)
                    {
                        foreach (Party party in mentionedPartiesTotal)
                        {
                            if (party.ID == feedParty.Party.ID) {
                                feedParty.LastFetchTime = now;
                                feedParty.ArticlesCount++;
                                if (article.Sentiment == Sentiment.positive)
                                    feedParty.PosArticlesCount++;
                                else if (article.Sentiment == Sentiment.negative)
                                    feedParty.NegArticlesCount++;
                            }
                        }
                        foreach (Party party in mentionedPartiesByTheirMembers)
                        {
                            if (party.ID == feedParty.Party.ID)
                            {
                                feedParty.ArticlesMemberCount++;
                            }
                        }
                    }
                }
                //Update feedStatistics
                foreach (FeedStatistic feedStatistic in feedStatistics)
                {
                    if (article.Feed.ID == feedStatistic.Feed.ID)
                    {
                        feedStatistic.ArticlesCount++;
                        if (article.Sentiment != null)
                            feedStatistic.PoliticalArticlesCount++;
                        if (article.Sentiment == Sentiment.positive)
                            feedStatistic.PosPoliticalArticlesCount++;
                        else if (article.Sentiment == Sentiment.negative)
                            feedStatistic.NegPoliticalArticlesCount++;
                        if (mentionedPartiesTotal.Count() > 1)
                            feedStatistic.MultiPartyArticlesCount++;
                        feedStatistic.PartyMentionsCount += mentionedPartiesTotal.Count();
                        feedStatistic.Date = now;
                    }
                }
            }
        }

        public static void UpdateMemberMentions(OnlineMediaAnalyzerContext db, List<Article> articles, List<MemberMention> memberMentions, List<PartyMember> partyMembers)
        {
            foreach (Article article in articles)
            {
                List<PartyMember> mentionedMembers = GetMemberMentions(article, partyMembers);
                foreach (MemberMention memberMention in memberMentions)
                {
                    foreach (PartyMember partyMember in mentionedMembers)
                    {
                        if (memberMention.PartyMember.ID == partyMember.ID && article.FeedID == memberMention.FeedID)
                        {
                            memberMention.MentionsCount++;
                            if (article.Sentiment == Sentiment.positive)
                                memberMention.PosMentionsCount++;
                            else if (article.Sentiment == Sentiment.negative)
                                memberMention.NegMentionsCount++;
                        }
                    }
                }
            }
        }

        public static List<Party> GetPartyMentions(Article article, List<PartyKeyword> partyKeywords)
        {
            List<Party> parties = new List<Party>();
            if (article.Sentiment == null)
                return parties;

            string title = article.Title;
            string description = article.Description;
            string lowerTitle = title.ToLower();
            string lowerDescription = description.ToLower();

            foreach (PartyKeyword keyword in partyKeywords)
            {
                string lowerKeyword = keyword.Keyword.ToLower();
                if (lowerTitle.Contains(lowerKeyword) || lowerDescription.Contains(lowerKeyword))
                {
                    bool exists = false;
                    foreach (Party party in parties)
                    {
                        if (party.ID == keyword.Party.ID)
                        {
                            exists = true;
                            break;
                        }
                    }
                    if (!exists)
                    {
                        parties.Add(keyword.Party);
                    } 
                }
            }
            return parties;
        }
        public static List<PartyMember> GetMemberMentions(Article article, List<PartyMember> partyMembers)
        {
            List<PartyMember> members = new List<PartyMember>();
            if (article.Sentiment == null)
                return members;

            string title = article.Title;
            string description = article.Description;
            string lowerTitle = title.ToLower();
            string lowerDescription = description.ToLower();

            foreach (PartyMember member in partyMembers)
            {
                if (title.Contains(member.Name) || description.Contains(member.Name))
                {
                    bool exists = false;
                    foreach (PartyMember member2 in members)
                    {
                        if (member.ID == member2.ID)
                        {
                            exists = true;
                            break;
                        }
                    }
                    if (!exists)
                    {
                        members.Add(member);
                    } 
                }
            }
            return members;
        }
        public static List<Party> MemberMentionsToParties(List<PartyMember> partyMembers)
        {
            List<Party> parties = new List<Party>();
            foreach (PartyMember member in partyMembers)
            {
                bool exists = false;
                foreach (Party party in parties)
                {
                    if (member.Party.ID == party.ID)
                    {
                        exists = true;
                        break;
                    }
                }
                if (!exists)
                {
                    parties.Add(member.Party);
                }
            }
            return parties;
        }
        public static List<Party> SumPartyAndMemberMentions(List<Party> parties, List<PartyMember> partyMembers)
        {
            foreach (PartyMember member in partyMembers)
            {
                bool exists = false;
                foreach (Party party in parties)
                {
                    if (member.Party.ID == party.ID)
                    {
                        exists = true;
                        break;
                    }
                }
                if (!exists)
                {
                    parties.Add(member.Party);
                }
            }
            return parties;
        }

    }
}